package com.nononsenseapps.feeder.ui.reader.sample

import android.annotation.SuppressLint
import android.os.Bundle
import android.text.Spanned
import android.view.Gravity
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.ListView
import android.widget.TextView
import androidx.annotation.MainThread
import androidx.core.widget.NestedScrollView
import com.gitee.wsl.common.ui.ext.selector
import com.gitee.wsl.common.ui.theme.inject.theme
import com.gitee.wsl.ext.base.isFalse
import com.google.android.material.bottomappbar.BottomAppBar
import com.kongzue.stacklabelview.StackLabel
import com.lxj.xpopup.XPopup
import com.lxj.xpopup.interfaces.XPopupCallback
import com.lzf.easyfloat.EasyFloat
import com.lzf.easyfloat.enums.SidePattern
import com.lzf.easyfloat.interfaces.OnInvokeView
import com.nononsenseapps.feeder.theme.appTheme
import com.nononsenseapps.feeder.ui.R
import com.nononsenseapps.feeder.ui.base.CoroutineScopedFragment
import com.nononsenseapps.feeder.util.IntentUtils
import com.nononsenseapps.feeder.util.PrefUtils
import com.nononsenseapps.feeder.util.openLinkInBrowser
import fr.gaulupeau.apps.Poche.tts.source.TtsHost
import io.noties.markwon.MarkdownViewer
import io.noties.markwon.base.core.spans.HeadingSpan
import io.noties.markwon.listener.MediaClickListener
import org.joda.time.format.DateTimeFormat
import timber.log.Timber
import java.util.Locale
import kotlin.properties.Delegates

abstract class AbstractBaseReaderFragment : CoroutineScopedFragment(), TtsHost {
    protected val dateTimeFormat = DateTimeFormat.forStyle("FM").withLocale(Locale.getDefault())
    protected lateinit var fragmentReader: View
    protected lateinit var bodyTextView: MarkdownViewer
    protected lateinit var titleTextView: TextView
    protected lateinit var mAuthorTextView: TextView
    protected lateinit var mFeedTitleTextView: TextView
    protected lateinit var scrollBodyView: LinearLayout
    protected lateinit var storyWordCount: TextView
    protected lateinit var storySpeak: ImageView
    protected lateinit var scrollView: NestedScrollView

    protected lateinit var itemFeatureView : TextView
    protected lateinit var itemTagsView : StackLabel

    protected lateinit var bottomAppBar : BottomAppBar

    protected var windowHeight by Delegates.notNull<Int>()
    var xPopupCallback: XPopupCallback? = null

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?): View {
        // Inflate the layout for this fragment
        val theLayout = getLayoutId()
        val rootView = inflater.inflate(theLayout, container, false)

        fragmentReader=rootView.findViewById(R.id.fragment_reader)
        fragmentReader.setBackgroundColor(PrefUtils.getReadBackgroundColor(requireActivity()))

        scrollView = rootView.findViewById(R.id.scroll_view)

        titleTextView = rootView.findViewById(R.id.story_title)
        bodyTextView = rootView.findViewById(R.id.story_body)

        autoSizePreLoadResolverDef.init( bodyTextView.maxWidth, bodyTextView.textSize)

        bodyTextView.init(markwon)

        mAuthorTextView = rootView.findViewById(R.id.story_author)
        mFeedTitleTextView = rootView.findViewById(R.id.story_feedtitle)
        scrollBodyView=rootView.findViewById(R.id.scroll_body_view)

        storyWordCount = rootView.findViewById(R.id.story_word_count)

        storySpeak = rootView.findViewById(R.id.story_speak)
        storySpeak.setColorFilter(R.color.reader_author_color)

        itemFeatureView = rootView.findViewById(R.id.feedItem_feature)
        itemTagsView = rootView.findViewById(R.id.feedItem_tag)
        bottomAppBar=rootView.findViewById(R.id.bottomAppBar)

        bodyTextView.setUrlClickListener {
            urlClickListener(it)
        }

        bodyTextView.setMediaClickListener(object :
            MediaClickListener {
            override fun onImageclickListener(urlLink: String?) {
                urlLink?.let {
                    showImagePreview(requireContext(), bodyTextView.text as Spanned, urlLink, xPopupCallback)
                }
            }

            override fun onAudioClickListener(urlLink: String?) {
//                urlLink?.let { url ->
//                    if (PrefUtils.shouldLoadVideoInside(activity!!)) {
//                        getCurrentFeedItem().let {
//                            showAudioPreview(activity!!, url, it.title, "audio/*", it.feedTitle, it.imageUrl ?: "")
//                        }
//
//                    } else
//                        IntentUtils.startActivityByUrl(activity!!, urlLink, "play audio", "audio/*")
//                }
            }

            override fun onVideoClickListener(urlLink: String?) {
                urlLink?.let {
                    if (PrefUtils.shouldLoadVideoInside(activity!!))
                        showVideoPreview(activity!!, it)
                    else {
                        IntentUtils.startActivityByUrl(activity!!, it, "play video", "video/*")
                    }
                }
            }

            override fun onIframeClickListener(urlLink: String?) {
                urlLink?.let {
                    urlClickListener(it)
                }
            }
        })

        windowHeight=resources.displayMetrics.heightPixels

        scrollView.setOnScrollChangeListener(View.OnScrollChangeListener { v, scrollX, scrollY, oldScrollX, oldScrollY ->
            bodyTextView.parentScrollChanged(scrollX, scrollY,oldScrollY,windowHeight)
        })

        initReadTextSize()

        bottomAppBar.setOnMenuItemClickListener { item ->
            onOptionsItemSelectedWithFab(item.itemId, bottomAppBar)
            false
        }

        return rootView
    }


    @SuppressLint("SetTextI18n")
    @MainThread
    fun updateUi(title:String, markdownConstant:String){
       Timber.d("updateUi:$title")
           titleTextView.text = title
           storyWordCount.text = "${markdownConstant.length} word"
           bodyTextView.setMarkdownString(markdownConstant)
           // Update state of notification toggle
           requireActivity().invalidateOptionsMenu()
    }


   protected open fun initTheme() {
        val color = appTheme.colorScheme.text.toInt()
        titleTextView.theme(appTheme)
        mAuthorTextView.theme(appTheme)
        mFeedTitleTextView.theme(appTheme)
        storyWordCount.theme(appTheme)
        bodyTextView.setTextColor(color)
        Timber.d("change theme read body text color to ${appTheme.colorScheme.text}")
    }

    fun initReadTextSize() {
        val textSize = PrefUtils.getReadTextSize(requireContext())
        if (textSize != 0f)
            bodyTextView.setTextSize(textSize)
    }

    abstract fun getLayoutId(): Int


    fun isSrollBottom(): Boolean {
        return scrollBodyView.height <= scrollView.scrollY + scrollView.height
    }


    override fun onStop() {
        super.onStop()
        /*feedItemViewModel.clearCache()
        bodyTextView.text  = null
        titleTextView.text = null
        feedItemViewModel.readLastScrollLine = scrollView.scrollY
        EasyFloat.isShow("outline").isTrue { EasyFloat.dismiss("outline") }*/
    }

    fun getHeadHight(): Int {
        return titleTextView.height + mFeedTitleTextView.height
    }

    open fun urlClickListener(link: String) {
       openLinkInBrowser(requireContext(), link)
    }

    abstract fun navigateToCodeViewFragment()


    protected fun changeTheme() {
        val themeList = appTheme.getSuportColorThemeList()
        requireContext().selector(themeList, getString(R.string.change_theme)) { _, item, _ ->
            appTheme.changeTheme(item)
            initTheme()
        }
    }

    fun showOutLinePop(view: View) {
        val text = bodyTextView.text
        if (text is Spanned) {
            val headingSpansArray = text.getSpans(0, text.length, HeadingSpan::class.java)
            if (headingSpansArray.isEmpty()) return
            val headingSpans = headingSpansArray.asList().reversed()

            val headerAdapter = HeaderAdapter(requireContext(), 0, text) {
                // 获取所在的行数
                val lineOffset = bodyTextView.layout.getLineForOffset(text.getSpanStart(it));
                scrollView.scrollTo(0, getHeadHight() + bodyTextView.layout.getLineTop(lineOffset))
            }
            headerAdapter.addAll(headingSpans)
            XPopup.Builder(requireContext()).atView(view)
                .asCustom(CustomAttachPopup(requireContext(), headerAdapter)).show()
        }
    }

    fun showOutLine() {
        EasyFloat.isShow("outline").isFalse(
            EasyFloat.with(requireActivity())
                .setTag("outline")
                .setSidePattern(SidePattern.DEFAULT)
                .setDragEnable(true)
                .setGravity(Gravity.END, 0, 100)
                .setLayout(R.layout.float_reader_outline, OnInvokeView { view ->
                    view.findViewById<ImageView>(R.id.ivClose).setOnClickListener {
                        EasyFloat.dismiss("outline")
                    }
                    val outLineListView = view.findViewById<ListView>(R.id.iv_outline_head).apply {
                        //监听 ListView 的触摸事件，手指触摸时关闭拖拽，手指离开重新开启拖拽
                        setOnTouchListener { _, event ->
                            EasyFloat.dragEnable(event?.action == MotionEvent.ACTION_UP, "outline")
                            false
                        }
                    }
                    initOutlineListView(outLineListView)
                })
            ::show
        )
    }

    open fun  initOutlineListView(listView:ListView){
        val spanned = bodyTextView.text as Spanned
        val text = bodyTextView.text

        val headerAdapter = HeaderAdapter(requireContext(), 0, spanned) {
            // 获取所在的行数
            val lineOffset =
                bodyTextView.layout.getLineForOffset(spanned.getSpanStart(it));
            scrollView.scrollTo(
                0,
                getHeadHight() + bodyTextView.layout.getLineTop(lineOffset)
            )
        }

        if (text is Spanned) {
            val headingSpans =
                text.getSpans(0, text.length, HeadingSpan::class.java)
            headerAdapter.addAll(headingSpans.asList().reversed())
        }

        listView.adapter = headerAdapter
    }

    override fun ensureTextRangeVisible(): Boolean {
        return false
    }

    override fun getScrollY(): Int {
        return scrollView.scrollY
    }

    override fun getViewHeight(): Int {
        return scrollView.height
    }

    override fun scrollTo(y: Int) {
        scrollView.smoothScrollTo(0, y)
    }

    override fun previousArticle(): Boolean = false

    override fun nextArticle(): Boolean = false

    abstract fun onOptionsItemSelectedWithFab(id :Int,view: View?=null)
}